from inspect import iscoroutinefunction
from typing import Tuple, List, Optional, Literal

from fastapi import Response, HTTPException, Request
from fastapi.responses import PlainTextResponse

from my_webdav.resource_model import LFSModel, LocalResourceCreator, ResourceModel, ResourceCreator


class BaseHandler(object):

    @staticmethod
    def options():
        allow_method = "GET, HEAD, POST, PUT, DELETE, OPTIONS, PROPFIND, PROPPATCH, MKCOL, MOVE, COPY"
        headers = {
            "Allow": allow_method,
            "Content-length": "0",
            "DAV": "1, 2",
            "MS-Author-Via": "DAV"
        }
        return PlainTextResponse(status_code=200, headers=headers)

    @staticmethod
    async def propfind(res_model: ResourceModel, info: Tuple[List[str], bool, bool, str]):
        props, only_propname, all_prop, depth = info
        if iscoroutinefunction(res_model.prop_xml):
            xml_bytes = await res_model.prop_xml(depth, props, only_propname, all_prop)
        else:
            xml_bytes = res_model.prop_xml(depth, props, only_propname, all_prop)
        resp = Response(
            content=xml_bytes,
            status_code=207,
            media_type="text/xml"
        )
        return resp

    @staticmethod
    async def get(res_model: ResourceModel, rng: Optional[str] = None, head_only: bool = False):
        if res_model.FLG == 1:
            # 禁止对Collection做GET请求
            raise HTTPException(405)

        if iscoroutinefunction(res_model.response_for_get):
            resp = await res_model.response_for_get(rng, head_only=head_only)
        else:
            resp = res_model.response_for_get(rng, head_only=head_only)
        return resp

    @staticmethod
    async def head(res_model: ResourceModel, rng: Optional[str] = None):
        return await BaseHandler.get(res_model, rng, True)

    @staticmethod
    async def mkcol(creator: ResourceCreator):
        await creator.make_collection()
        resp = Response(status_code=201)
        return resp

    @staticmethod
    async def put_file(creator: LocalResourceCreator, request: Request):
        await creator.put_file(request)
        resp = Response(status_code=200)
        return resp

    @staticmethod
    async def delete(res_model: ResourceModel):
        await res_model.delete()
        resp = Response(status_code=200)
        return resp

    @staticmethod
    async def lock(res_model: LFSModel):
        await res_model.lock()
        resp = Response(status_code=200)
        return resp

    @staticmethod
    async def unlock(res_model: LFSModel):
        await res_model.unlock()
        resp = Response(status_code=200)
        return resp

    @staticmethod
    async def move(res_model: ResourceModel, dst: Optional[str], overwrite: Literal["F", "T"]):
        await res_model.move(dst, overwrite)
        resp = Response(status_code=201)
        return resp

    @staticmethod
    async def copy(
            res_model: ResourceModel, dst: Optional[str], overwrite: Literal["F", "T"],
            depth: Literal["0", "infinity"]
    ):
        await res_model.copy(dst, overwrite, depth)
        resp = Response(status_code=201)
        return resp
